package robocup.component.infotypes;

import java.util.ArrayList;

/**
 * This class holds the set of elements, which can be seen by the coach. These
 * are the teammates (<code>ownPlayers</code>), the opponents (<code>
 * otherPlayers</code>),
 * and the ball.
 */
public class CoachVisualInfo
    extends Info {

  /**
   * A list contain all seen teammates.
   */
  private final ArrayList<CoachPlayerInfo> ownPlayers    = new ArrayList<CoachPlayerInfo>();

  /**
   * A list containing all seen opponents.
   */
  private final ArrayList<CoachPlayerInfo> otherPlayers  = new ArrayList<CoachPlayerInfo>();

  /**
   * The seen ball.
   */
  private CoachBallInfo              ball          = new CoachBallInfo(0, 0, 0,
                                                       0, 0);

  /**
   * The name of the own team.
   */
  private String                     ownTeamName   = null;

  /**
   * The opponents team name.
   */
  private String                     otherTeamName = null;

  /**
   * CoachVI consists of seen (global) players and ball! It needs the
   * ownTeam-Name to identify own players (own / other players perceived)
   * 
   * @param iCycle -
   *          when was the VI received
   * @param ownTeamName -
   *          to check, which agents belong to own or other team
   */
  public CoachVisualInfo(
      final int iCycle,
      final String ownTeamName) {

    super(iCycle);
    this.infoType = Info.TYPE_COACHVI;
    this.ownTeamName = ownTeamName;
  }

  /**
   * Resets the lists for own and opponents seen players, in order to reuse
   * them.
   */
  public void reset() {

    for (final int i = 0; i < this.ownPlayers.size();) {
      this.ownPlayers.remove(0);
    }
    for (final int i = 0; i < this.otherPlayers.size();) {
      this.otherPlayers.remove(0);
    }
  }

  /**
   * Creates a new CoachPlayer and adds him to the list (own or other, depending
   * on the team) Warning: do not buffer, always create a new player, because
   * they are used directly in coach-tactics
   * 
   * @param cycle -
   *          the cycle
   * @param dyPos -
   *          the y-position in robocup-coordinates, has to be changed with x in
   *          our coordinate-system
   * @param dxPos -
   *          the x-position in robocup-coordinates, has to be changed with y in
   *          our coordinate-system
   * @param dyVel -
   *          the y velocity, has to be changed with x-velocity according to our
   *          changed coordinate system
   * @param dxVel -
   *          the x velocity, has to be changed with y-velocity according to our
   *          changed coordinate system
   * @param iNum -
   *          the players tricot number
   * @param dBodyAngel -
   *          his body angle
   * @param dHeadAngel -
   *          his head-angle
   * @param dPointDir -
   *          the direction he points to
   * @param tackle -
   *          is tackling (blocked?)
   */
  public void addPlayer(final String team,
      final boolean own,
      final int cycle,
      final double dyPos,
      final double dxPos,
      final double dyVel,
      final double dxVel,
      final int iNum,
      final double dBodyAngle,
      final double dHeadAngle,
      final double dPointDir,
      final boolean goalie,
      final boolean tackle) {

    final CoachPlayerInfo cpi = new CoachPlayerInfo("", 0, 0, 0, 0, 0, 0, 0, 0, 0,
        false, false);
    cpi.setTeamName(team);
    cpi.setCycle(cycle);
    cpi.setYPos(dxPos);
    cpi.setXPos(dyPos);
    cpi.setYSpeed(dxVel);
    cpi.setXSpeed(dyVel);
    cpi.setPlayerNumber(iNum);
    cpi.setBodyAngle(dBodyAngle);
    cpi.setNeckAngle(dHeadAngle);
    cpi.setPointDirection(dPointDir);
    cpi.setGoalie(goalie);
    cpi.setTackle(tackle);

    if (own) {
      this.addOwn(cpi);
    }
    else {
      this.addOther(cpi);
    }
  }

  /**
   * Adds own player to the list
   * 
   * @param info -
   *          a player
   */
  private void addOwn(final CoachPlayerInfo info) {

    if (this.cycle == 0) {
      this.cycle = info.getCycle();
    }
    this.ownPlayers.add(info);
  }

  /**
   * Adds other player to the list
   * 
   * @param info -
   *          a player
   */
  private void addOther(final CoachPlayerInfo info) {

    if (this.cycle == 0) {
      this.cycle = info.getCycle();
    }
    this.otherPlayers.add(info);
  }

  /**
   * Creates a new ball with given values
   * 
   * @param cycle -
   *          the game cycle
   * @param dyPos -
   *          its y position, which will be x in out coordinates
   * @param dxPos -
   *          its x position, which will be y in out coordinates
   * @param dyVel -
   *          its y velocity, which will be y in out coordinates
   * @param dxVel -
   *          its x velocity, which will be y in out coordinates
   */
  public void setBall(final int cycle,
      final double dyPos,
      final double dxPos,
      final double dyVel,
      final double dxVel) {

    this.ball = new CoachBallInfo(0, 0, 0, 0, 0);
    this.ball.setCycle(cycle);
    this.ball.setYPos(dxPos);
    this.ball.setXPos(dyPos);
    this.ball.setYSpeed(dxVel);
    this.ball.setXSpeed(dyVel);
  }

  /**
   * @return Returns the ball.
   */
  public CoachBallInfo getCoachBall() {

    return this.ball;
  }

  /**
   * @return Returns the otherPlayers.
   */
  public CoachPlayerInfo[] getOtherPlayers() {

    return (this.otherPlayers.toArray(new CoachPlayerInfo[this.otherPlayers
        .size()]));
  }

  /**
   * @return Returns the ownPlayers.
   */
  public CoachPlayerInfo[] getOwnPlayers() {

    return (this.ownPlayers
        .toArray(new CoachPlayerInfo[this.ownPlayers.size()]));
  }

  /**
   * @return Returns the otherTeamName.
   */
  public String getOtherTeamName() {

    return this.otherTeamName;
  }

  /**
   * @param otherTeamName
   *          The otherTeamName to set.
   */
  public void setOtherTeamName(final String otherTeamName) {

    this.otherTeamName = otherTeamName;
  }

  /**
   * @return Returns the ownTeamName.
   */
  public String getOwnTeamName() {

    return this.ownTeamName;
  }
}
